﻿using JESAI.HtmlTemplate.Pdf;
#if !NET45
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
#else
using System.Web.Mvc;
using System.Web;
using RazorEngine.Compilation.ImpromptuInterface.Optimization;
#endif

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JESAI.HtmlTemplate.Pdf.Utils;

namespace Microsoft.AspNetCore.Mvc
{
    public class PDFCallRedirectResult<T> : ActionResult where T:class
    {
        private const string ActionNameKey = "action";
        public T Value { get; private set; }
        public Func<byte[], byte[]> _func { get; private set; }
        public string FileRootPath { get; private set; }= "D:\\PdfFile";
        public string FileName { get; private set; }
        public bool IsSaveFile { get; private set; }
        public string FilePath { get; private set; }
        public string RemotePath { get; private set; }
        public string HashCode { get; private set; }

        //public PDFCallResult(T value,Func<byte[], byte[]> func,bool isSaveFile=true ,string fileName=null,string fileRootPath=null)
        //{
        //    Value = value;
        //    _func = func;
        //    FileName = fileName;
        //    IsSaveFile = isSaveFile;
        //    if (!string.IsNullOrWhiteSpace(fileRootPath))
        //    {
        //        FileRootPath = fileRootPath;
        //    }
        //}
        public PDFCallRedirectResult(T value, Func<byte[], byte[]> func,string remotePath, bool isSaveFile = true, string fileName = null, string fileRootPath = null, string hashCode = null)
        {
            Value = value;
            _func = func;
            FileName = fileName;
            IsSaveFile = isSaveFile;
            RemotePath = remotePath;
            HashCode = hashCode;
            if (!string.IsNullOrWhiteSpace(fileRootPath))
            {
                FileRootPath = fileRootPath;
            }
        }
        public PDFCallRedirectResult(T value, Func<byte[], byte[]> func, string remotePath, out string filePath, bool isSaveFile = true, string fileName = null, string fileRootPath = null,string hashCode=null)
        {
            Value = value;
            _func = func;
            FileName = fileName;
            IsSaveFile = isSaveFile;
            filePath = FilePath;
            RemotePath = remotePath;
            HashCode = hashCode;
            if (!string.IsNullOrWhiteSpace(fileRootPath))
            {
                FileRootPath = fileRootPath;
            }
        }
        //public override async Task ExecuteResultAsync(ActionContext context)
        // {
        //     var services = context.HttpContext.RequestServices;
        //    // var executor = services.GetRequiredService<IActionResultExecutor<PDFResult>>();
        //     //await executor.ExecuteAsync(context, new PDFResult(this));
        // }
#if !NET45
        private static string GetActionName(ActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (!context.RouteData.Values.TryGetValue(ActionNameKey, out var routeValue))
            {
                return null;
            }

            var actionDescriptor = context.ActionDescriptor;
            string normalizedValue = null;
            if (actionDescriptor.RouteValues.TryGetValue(ActionNameKey, out var value) &&
                !string.IsNullOrEmpty(value))
            {
                normalizedValue = value;
            }

            var stringRouteValue = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
            if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
            {
                return normalizedValue;
            }

            return stringRouteValue;
        }
#endif

#if !NET45
        public override async Task ExecuteResultAsync(ActionContext context)
          {
            var viewName = GetActionName(context);
            var services = context.HttpContext.RequestServices;
            var exportPdfByHtmlTemplate=services.GetService<IExportPdfByHtmlTemplate>();
            var viewEngine=services.GetService<ICompositeViewEngine>();
            var tempDataProvider = services.GetService<ITempDataProvider>();
            var result = viewEngine.FindView(context, viewName, isMainPage: true);
#else
        public override void ExecuteResult(ControllerContext context)
        {
            var viewName = context.RouteData.Values["action"].ToString();
            var result = ViewEngines.Engines.FindView(context, viewName, null);
            context.HttpContext.Response.Clear();
            IExportPdfByHtmlTemplate exportPdfByHtmlTemplate = new PdfByHtmlTemplateExporter ();
#endif
            if (result.View == null)
                throw new ArgumentException($"名称为：{viewName}的视图不存在，请检查!");
           
            // context.HttpContext.Response.ContentType = "application/pdf";
            //context.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=test.pdf");                    
            var html = "";
            using (var stringWriter = new StringWriter())
            {                            
#if !NET45
                var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = Value };
                var viewContext = new ViewContext(context, result.View, viewDictionary, new TempDataDictionary(context.HttpContext, tempDataProvider), stringWriter, new HtmlHelperOptions());

                await result.View.RenderAsync(viewContext);
#else
                var viewDictionary = new ViewDataDictionary(new ModelStateDictionary()) { Model = Value };
                var viewContext = new ViewContext(context, result.View, viewDictionary, context.Controller.TempData, stringWriter);
                result.View.Render(viewContext, stringWriter);
                result.ViewEngine.ReleaseView(context, result.View);
#endif
                html = stringWriter.ToString();

            }
            byte[] buff = new byte[] { };
            if (IsSaveFile)
            {
                if (!Directory.Exists(FileRootPath))
                    Directory.CreateDirectory(FileRootPath);
                if(string.IsNullOrWhiteSpace(HashCode))
                    HashCode = MD5HashUtil.GetMD5HashString(Value);
                FilePath = FileRootPath + "\\"+(FileName ?? "") + HashCode + ".pdf";
             
                //var tpl=File.ReadAllText(result.View.Path);
#if !NET45
                //byte[] buff=await exportPdfByHtmlTemplate.ExportByHtmlPersistAsync<T>(Value,html);
                if (File.Exists(filePath))
                    buff = await File.ReadAllBytesAsync(filePath);
                else
                {
                    buff = exportPdfByHtmlTemplate.ExportByHtmlAsync<T>(html).Result;
                    buff = _func.Invoke(buff);
                    await File.WriteAllBytesAsync(filePath, buff);
                }
#else


            if (!File.Exists(FilePath))
            {
                buff =  exportPdfByHtmlTemplate.ExportByHtml<T>(html);
                buff = _func.Invoke(buff);
                File.WriteAllBytes(FilePath, buff);
            }

#endif
            }
            else
            {
#if !NET45
                buff = exportPdfByHtmlTemplate.ExportByHtmlAsync<T>(html).Result;
                buff = _func.Invoke(buff);
#else
                buff =  exportPdfByHtmlTemplate.ExportByHtml<T>(html);
                buff = _func.Invoke(buff);
#endif
            }
            string RedirectUrl = FilePath.Replace(FileRootPath, RemotePath);
            context.HttpContext.Response.Redirect(RedirectUrl);



        }
    }
}
